/* global Worker tabs */

import webviews from '../webviews.js';
import { db } from '../util/database.js';
import searchEngine from '../util/searchEngine.js';
import urlParser from '../util/urlParser.js';

const places = {
  savePage: function (tab, extractedText) {
    /* this prevents pages that are immediately left from being saved to history, and also gives the page-favicon-updated event time to fire (so the colors saved to history are correct). */
    setTimeout(function () {
      if (tab) {
        const data = {
          url: urlParser.getSourceURL(tab.url), // for PDF viewer and reader mode, save the original page URL and not the viewer URL
          title: tab.title,
          color: tab.backgroundColor,
          extractedText: extractedText,
        };

        places.worker.postMessage({
          action: 'updatePlace',
          pageData: data,
          flags: {
            isNewVisit: true,
          },
        });
      }
    }, 500);
  },
  receiveHistoryData: function (tab, args) {
    // called when js/preload/textExtractor.js returns the page's text content

    var data = args[0];
    // console.log("receiveHistoryData");
    // console.log(tab);
    if(!tab.url) return;
    if (tab.url.startsWith('data:') || tab.url.length > 5000) {
      /*
      very large URLs cause performance issues. In particular:
      * they can cause the database to grow abnormally large, which increases memory usage and startup time
      * they can cause the browser to hang when they are displayed in search results
      To avoid this, don't save them to history
      */
      return;
    }

    /* if the page is an internal page, it normally shouldn't be saved,
     unless the page represents another page (such as the PDF viewer or reader view) */
    var isNonIndexableInternalPage =
      urlParser.isInternalURL(tab.url) &&
      urlParser.getSourceURL(tab.url) === tab.url;
    var isSearchPage = !!searchEngine.getSearch(tab.url);

    // full-text data from search results isn't useful
    if (isSearchPage) {
      data.extractedText = '';
    }

    // don't save to history if in private mode, or the page is a browser page (unless it contains the content of a normal page)
    if (tab.private === false && !isNonIndexableInternalPage) {
      places.savePage(tab, data.extractedText);
    }
  },
  callbacks: [],
  addWorkerCallback: function (callback) {
    const callbackId = Date.now() / 1000 + Math.random();
    places.callbacks.push({ id: callbackId, fn: callback });
    return callbackId;
  },
  runWorkerCallback: function (id, data) {
    for (var i = 0; i < places.callbacks.length; i++) {
      if (places.callbacks[i].id === id) {
        places.callbacks[i].fn(data);
        places.callbacks.splice(i, 1);
      }
    }
  },
  deleteHistory: function (url) {
    places.worker.postMessage({
      action: 'deleteHistory',
      pageData: {
        url: url,
      },
    });
  },
  deleteAllHistory: function () {
    places.worker.postMessage({
      action: 'deleteAllHistory',
    });
  },
  searchPlaces: function (text, callback, options) {
    const callbackId = places.addWorkerCallback(callback);
    places.worker.postMessage({
      action: 'searchPlaces',
      text: text,
      callbackId: callbackId,
      options: options,
    });
  },
  searchPlacesFullText: function (text, callback) {
    const callbackId = places.addWorkerCallback(callback);
    places.worker.postMessage({
      action: 'searchPlacesFullText',
      text: text,
      callbackId: callbackId,
    });
  },
  getPlaceSuggestions: function (url, callback) {
    const callbackId = places.addWorkerCallback(callback);
    places.worker.postMessage({
      action: 'getPlaceSuggestions',
      text: url,
      callbackId: callbackId,
    });
  },
  onMessage: function (e) {
    // assumes this is from a search operation
    places.runWorkerCallback(e.data.callbackId, e.data.result);
  },
  updateItem: function (url, fields, callback) {
    const callbackId = places.addWorkerCallback(callback);
    places.worker.postMessage({
      action: 'updatePlace',
      pageData: {
        url: url,
        ...fields,
      },
      callbackId: callbackId,
    });
  },
  toggleBookmarked_url: function (url,title,callback) {
    // Toggles whether a URL is bookmarked or not
    // const url = tabs.get(tabid).url;
    console.log("toggleBookmarked_url");
    db.places
      .where('url')
      .equals(url)
      .first(function (item) {
        if (item && item.isBookmarked) {
          console.log("isBookmarked")
          places.updateItem(url, { isBookmarked: false }, function () {
            console.log("callback false")
            callback(false);
          });
        } else {
          // if this page is open in a private tab, the title may not be saved already, so it needs to be included here
          console.log("new item")
          places.updateItem(
            url,
            {
              isBookmarked: true,
              title: title,
            },
            function () {
              console.log("callback true")
              callback(true);
            }
          );
        }
      });
  },

  toggleTag: function (url, tag) {
    db.places
      .where('url')
      .equals(url)
      .first(function (item) {
        if (!item) {
          return;
        }
        if (item.tags.includes(tag)) {
          item.tags = item.tags.filter((t) => t !== tag);
        } else {
          item.tags.push(tag);
        }
        places.worker.postMessage({
          action: 'updatePlace',
          pageData: {
            url: url,
            tags: item.tags,
          },
        });
      });
  },
  getSuggestedTags: function (url, callback) {
    const callbackId = places.addWorkerCallback(callback);
    places.worker.postMessage({
      action: 'getSuggestedTags',
      pageData: {
        url: url,
      },
      callbackId: callbackId,
    });
  },
  getAllTagsRanked: function (url, callback) {
    const callbackId = places.addWorkerCallback(callback);
    places.worker.postMessage({
      action: 'getAllTagsRanked',
      pageData: {
        url: url,
      },
      callbackId: callbackId,
    });
  },
  getSuggestedItemsForTags: function (tags, callback) {
    const callbackId = places.addWorkerCallback(callback);
    places.worker.postMessage({
      action: 'getSuggestedItemsForTags',
      pageData: {
        tags: tags,
      },
      callbackId: callbackId,
    });
  },
  autocompleteTags: function (tags, callback) {
    const callbackId = places.addWorkerCallback(callback);
    places.worker.postMessage({
      action: 'autocompleteTags',
      pageData: {
        tags: tags,
      },
      callbackId: callbackId,
    });
  },
  initialize: function () {
    //todo
    if (places.worker) {
      places.worker.terminate();
    }
    places.worker = new Worker('esbuild/placesWorker.js');
    places.worker.onmessage = places.onMessage;

    webviews.bindIPC('pageData', places.receiveHistoryData);
  },
};

places.initialize();
export default places;
